using System;
using System.ServiceModel.Channels;

namespace WcfExtensions.ServiceModel.Channels
{
    internal abstract class CompressionChannel<TChannelShape> : ChannelBase where TChannelShape : class, IChannel
    {
        private readonly MessageCompressor _compressor;
        private readonly TChannelShape _innerChannel;

        protected CompressionChannel(ChannelManagerBase channelManager, TChannelShape innerChannel)
            : base(channelManager)
        {
            if (innerChannel == null)
                throw new ArgumentNullException("innerChannel");

            _innerChannel = innerChannel;

            var factory = channelManager as CompressionChannelFactory<TChannelShape>;
            if (factory != null)
            {
                _compressor = new MessageCompressor(factory.Algorithm, factory.Level);
            }
            else
            {
                var listener = (CompressionChannelListener<TChannelShape>)channelManager;
                _compressor = new MessageCompressor(listener.Algorithm, listener.Level);
            }
        }

        protected TChannelShape InnerChannel
        {
            get { return _innerChannel; }
        }

        protected MessageCompressor Compressor
        {
            get { return _compressor; }
        }

        public override T GetProperty<T>()
        {
            return _innerChannel.GetProperty<T>();
        }

        #region CommunicationObject members

        protected override void OnAbort()
        {
            _innerChannel.Abort();
        }

        protected override IAsyncResult OnBeginClose(TimeSpan timeout,
                                                     AsyncCallback callback,
                                                     Object state)
        {
            return _innerChannel.BeginClose(timeout, callback, state);
        }

        protected override IAsyncResult OnBeginOpen(TimeSpan timeout,
                                                    AsyncCallback callback,
                                                    Object state)
        {
            return _innerChannel.BeginOpen(timeout, callback, state);
        }

        protected override void OnClose(TimeSpan timeout)
        {
            _innerChannel.Close(timeout);
        }

        protected override void OnEndClose(IAsyncResult result)
        {
            _innerChannel.EndClose(result);
        }

        protected override void OnEndOpen(IAsyncResult result)
        {
            _innerChannel.EndOpen(result);
        }

        protected override void OnOpen(TimeSpan timeout)
        {
            _innerChannel.Open(timeout);
        }

        #endregion
    }
}